/***************************************************************************
 *   Copyright (C) 2008 by Thomas Richards   *
 *   thomi@colon   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "application.h"
#include "settings.h"
#include "pluginmanager.h"
#include "project.h"
#include "scheduler/projectscheduler.h"

#include <QCoreApplication>
#include <QDir>
#include <QDebug>
#include <QStringList>

Application::Application(QObject *parent)
 : QObject(parent),
   m_pProjectScheduler(NULL)
{	
	parseConfig();
}


Application::~Application()
{
}

void Application::runDaemon()
{
	// user wants to run in daemon mode.
	m_pProjectScheduler = new ProjectScheduler(QDir::toNativeSeparators(
		QString(tr("%1/.cppanalyse/scheduler.xml")).arg(QDir::homePath())));
}

void Application::createProject(const QString &strProjectPath)
{
	// user wants to create a New Project:
	makeNewProject(strProjectPath);
}

void Application::runProject(const QString &strProjectPath)
{
	// make sure file exists and is .ini file before passing it to project:
	QFileInfo fi(strProjectPath);
	if (!fi.exists() || fi.suffix().compare("ini", Qt::CaseInsensitive) != 0)
	{
		qWarning() << "Project file:" << strProjectPath << " Either does not exist or is not an .ini file. Bailing";
		return;
	}
		
	// create project:
	Project *proj = new Project(fi.absolutePath(), this);
	connect(proj, SIGNAL(stateChanged(Project::tProjectState)), this, SLOT(projectStateChanged(Project::tProjectState)));
	proj->runProject(fi.absoluteFilePath());
}

void Application::parseConfig()
{
	// load settings:
	Settings settings;
	
	m_strPluginPath = settings.value("PluginPath", 
									 QDir::currentPath() + "/plugins/").toString();
	QDir pluginDir(m_strPluginPath);
	if (! pluginDir.exists())
	{
		qWarning() << "Plugin Path" << m_strPluginPath << "does not exist!";
		return;
	}
	
	scanPlugins();
}

void Application::scanPlugins()
{
	Q_ASSERT(m_strPluginPath != "");
	
	// plugins should be in three sub-folders:
	// browsers, getters, scanners
	QDir pluginDir(m_strPluginPath);
	Q_ASSERT(pluginDir.exists());
	
	PluginManager &plugMan = PluginManager::instance();
	
	// TODO - onl register files that are of a known type - i.e.- exclude .pyc files (for example)
	
	if (! pluginDir.cd("getters"))
	{
		qWarning() << "no 'getter' plugins installed! Check your installation!";
		return;
	}
	// get list of files:
	QFileInfoList files = pluginDir.entryInfoList(QDir::Files | QDir::Readable);
	while (! files.isEmpty())
	{
		QFileInfo fi = files.takeFirst();
		plugMan.registerPlugin(fi.absoluteFilePath(), PluginManager::PLUGIN_TYPE_GETTER);
	}
	pluginDir.cdUp();
	
	if (! pluginDir.cd("browsers"))
	{
		qWarning() << "no 'browser' plugins installed! Check your installation!";
		return;
	}
	// get list of files:
	files = pluginDir.entryInfoList(QDir::Files | QDir::Readable);
	while (! files.isEmpty())
	{
		QFileInfo fi = files.takeFirst();
		plugMan.registerPlugin(fi.absoluteFilePath(), PluginManager::PLUGIN_TYPE_BROWSER);
	}
	pluginDir.cdUp();
	
	if (! pluginDir.cd("scanners"))
	{
		qWarning() << "no 'scanner' plugins installed! Check your installation!";
		return;
	}
	// get list of files:
	files = pluginDir.entryInfoList(QDir::Files | QDir::Readable);
	while (! files.isEmpty())
	{
		QFileInfo fi = files.takeFirst();
		plugMan.registerPlugin(fi.absoluteFilePath(), PluginManager::PLUGIN_TYPE_SCANNER);
	}
	pluginDir.cdUp();
	
	if (! pluginDir.cd("output"))
	{
		qWarning() << "no 'output' plugins installed! Check your installation!";
		return;
	}
	// get list of files:
	files = pluginDir.entryInfoList(QDir::Files | QDir::Readable);
	while (! files.isEmpty())
	{
		QFileInfo fi = files.takeFirst();
		plugMan.registerPlugin(fi.absoluteFilePath(), PluginManager::PLUGIN_TYPE_OUTPUT);
	}
	pluginDir.cdUp();
}

void Application::printUsage()
{
	//\todo Make this proper stdout, don't use qDebug!
	qDebug() << "cppanalyse --np <path> | --rp <path>";
	qDebug();
	qDebug() << "Either --np or --rp must be specified!";
}

void Application::makeNewProject(const QString & strLocation)
{
	QDir projectDir(strLocation);
	if (! projectDir.exists() && !projectDir.mkpath(strLocation))
	{
		qWarning() << "Could not create project location:" << strLocation;
		return;
	}
	
	// create a new project, and tell it to create the project config:
	Project *proj = new Project(projectDir);
	proj->createNewProject();
}

void Application::projectStateChanged(Project::tProjectState nState)
{
	if (nState == Project::STATE_DONE)
	{
		emit quit();
	}
}


